﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Xml;
using Common.Utilities;
using Common.Utilities.Dispatcher;
using Common.Utilities.DLR;
using Workflows.Components.ETL.Properties;

namespace Workflows.Components.ETL
{
    /// <summary>
    /// 
    /// </summary>
    [Serializable]
    public class DataCleaningComponent:WorkflowComponentBase
    {
        #region props
        private DataCleaningInstruction _instruction;
        private DataCleaningOutput _output;

        /// <summary>an object that encapsulate instruction settings.</summary>
        public override InstructionBase Instruction
        {
            get { return _instruction; }
            set { _instruction =(DataCleaningInstruction) value; }
        }

        /// <summary>an object to encapsulate output</summary>
        public override ResultBase Output
        {
            get { return _output; }
            set { _output =(DataCleaningOutput) value; }
        }

        /// <summary></summary>
        public List<DataCleaningRule> DataCleaningRules
        {
            get
            {
                return this._instruction.DataCleaningRules;
            }
            set
            {
                this._instruction.DataCleaningRules = value;
            }
        }

        /// <summary></summary>
        public DataPipeSourceType SourceType
        {
            get
            {
                return this._instruction.SourceType;
            }
            set
            {
                this._instruction.SourceType = value;
            }
        }

        /// <summary></summary>
        public DataProviderType DbProvider
        {
            get
            {
                return this._instruction.DbProvider;
            }
            set
            {
                this._instruction.DbProvider = value;
            }
        }

        /// <summary></summary>
        public string ConnStr
        {
            get
            {
                return this._instruction.ConnStr;
            }
            set
            {
                this._instruction.ConnStr = value;
            }
        }

        /// <summary></summary>
        public string SelectSql
        {
            get
            {
                return this._instruction.SelectSql;
            }
            set
            {
                this._instruction.SelectSql = value;
            }
        }

        /// <summary></summary>
        public string GroupBy
        {
            get
            {
                return this._instruction.GroupBy;
            }
            set
            {
                this._instruction.GroupBy = value;
            }
        }

        /// <summary></summary>
        public string SortBy
        {
            get
            {
                return this._instruction.SortBy;
            }
            set
            {
                this._instruction.SortBy = value;
            }
        }

        /// <summary></summary>
        public string TblName
        {
            get
            {
                return this._instruction.TblName;
            }
            set
            {
                this._instruction.TblName = value;
            }
        }

        /// <summary></summary>
        public string RootFolderPath
        {
            get
            {
                return this._instruction.RootFolderPath;
            }
            set
            {
                this._instruction.RootFolderPath = value;
            }
        }

        /// <summary></summary>
        public string FileFilter
        {
            get
            {
                return this._instruction.FileFilter;
            }
            set
            {
                this._instruction.FileFilter = value;
            }
        }

        /// <summary></summary>
        public SearchOption FolderSearchOption
        {
            get
            {
                return this._instruction.FolderSearchOption;
            }
            set
            {
                this._instruction.FolderSearchOption = value;
            }
        }

        /// <summary></summary>
        public DataPipeSerializationMethod SerializationMethod
        {
            get { return this._instruction.SerializationMethod; }
            set { this._instruction.SerializationMethod = value; }
        }
        /// <summary></summary>
        public string CustomTypeAssemblyPath
        {
            get { return this._instruction.CustomTypeAssemblyPath; }
            set { this._instruction.CustomTypeAssemblyPath = value; }
        }
        /// <summary></summary>
        public string CustomTypeName
        {
            get { return this._instruction.CustomTypeName; }
            set { this._instruction.CustomTypeName = value; }
        }
        /// <summary></summary>
        public DataProviderType TgtDbProvider
        {
            get { return this._instruction.TgtDbProvider; }
            set { this._instruction.TgtDbProvider = value; }
        }
        /// <summary></summary>
        public string TgtConnStr
        {
            get { return this._instruction.TgtConnStr; }
            set { this._instruction.TgtConnStr = value; }
        }
        /// <summary></summary>
        public string TgtFolderPath
        {
            get { return this._instruction.TgtFolderPath; }
            set { this._instruction.TgtFolderPath = value; }
        }
        /// <summary></summary>
        public string TgtFileNameFormat
        {
            get { return this._instruction.TgtFileNameFormat; }
            set { this._instruction.TgtFileNameFormat = value; }
        }
        #endregion

        #region ctor
        /// <summary>
        /// 
        /// </summary>
        public DataCleaningComponent():base()
        {
            this.ComponentActivityType = WorkflowActivityType.SimpleActivity;
            this.ComponentCategory = WorkflowComponentCategory.ETL.ToString();
            this.Description = "Clean data by using code snippets";
            this.ComponentIcon = Resources.dtspipeline_2_106;
            this.ComponentImage = Resources.transfer2;
            this.ComponentName = "Clean Data";

            this._instruction = new DataCleaningInstruction(this.ComponentID, Guid.Empty, null,
                                                            DataPipeSourceType.RowProvider, DataProviderType.MSSQL,
                                                            string.Empty, string.Empty, string.Empty, string.Empty,
                                                            string.Empty, string.Empty, string.Empty,
                                                            SearchOption.TopDirectoryOnly,
                                                            DataPipeSerializationMethod.SaveToDB, string.Empty,
                                                            string.Empty, DataProviderType.MSSQL, string.Empty,
                                                            string.Empty, string.Empty);
            this._output = new DataCleaningOutput(this.ComponentID, Guid.Empty, null, 0, 0);
        }
        #endregion

        /// <summary><para>must implementable method to serialize activity settings to xml</para></summary>
        public override XmlNode Serialize(ref XmlDocument xDoc, ref XmlNode parentNode)
        {
            XmlNode xNode = base.Serialize(ref xDoc, ref parentNode);

            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "DataSourceType", ((int)this.SourceType).ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "DbProviderType", ((int)this.DbProvider).ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "ConnStr", this.ConnStr);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "SelectSql", this.SelectSql);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "GroupBy", this.GroupBy);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "SortBy", this.SortBy);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "TableName", this.TblName);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "RootFolderPath", this.RootFolderPath);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "FileFilter", this.FileFilter);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "SearchOption", ((int)this.FolderSearchOption).ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "SerializationMethod", ((int)this.SerializationMethod).ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "CustomTypeAssemblyFilePath", this.CustomTypeAssemblyPath);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "CustomTypeName", this.CustomTypeName);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "TgtDbProvider", ((int)this.TgtDbProvider).ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "TgtConnStr", this.TgtConnStr);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "TgtFolderPath", this.TgtFolderPath);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "TgtFileNamePattern", this.TgtFileNameFormat);

            if (this.DataCleaningRules != null && this.DataCleaningRules.Count > 0)
            {
                XmlNode ruleRootNode = XmlDataUtil.AddElement(ref xDoc, xNode, "DataCleaningRules");
                foreach (DataCleaningRule rule in this.DataCleaningRules)
                {
                    XmlNode ruleNode = XmlDataUtil.AddElement(ref xDoc, ruleRootNode, "DataCleaningRule");
                    XmlDataUtil.UpdateAttribute(ref xDoc, ruleNode, "DataCleaningRuleID", rule.DataCleaningRuleID.ToString());
                    XmlDataUtil.UpdateAttribute(ref xDoc, ruleNode, "RuleName", rule.RuleName);
                    XmlDataUtil.UpdateAttribute(ref xDoc, ruleNode, "ExternalReferences",
                                                StringUtil.ToString(rule.ExternalReferences));
                    XmlDataUtil.UpdateAttribute(ref xDoc, ruleNode, "TypeNameToEvaluate", rule.ObjectTypeNameToEvaluate);
                    XmlDataUtil.UpdateAttribute(ref xDoc, ruleNode, "CodeSnippet", rule.CodeSnippet);
                    XmlDataUtil.UpdateAttribute(ref xDoc, ruleNode, "TrueAction", ((int)rule.TrueAction).ToString());
                    XmlDataUtil.UpdateAttribute(ref xDoc, ruleNode, "FalseAction", ((int)rule.FalseAction).ToString());
                }
            }
            
            return xNode;
        }

        /// <summary><para>subclass must implement this method to instantiate activity from xml</para></summary>
        public override WorkflowComponentBase Instantiate(XmlNode xNode)
        {
            if (xNode.Attributes.GetNamedItem("Type").Value == this.GetType().FullName)
            {
                DataCleaningComponent component = base.Instantiate(xNode) as DataCleaningComponent;

                component.SourceType =
                    (DataPipeSourceType)
                    int.Parse(XmlDataUtil.GetAttributeValue(xNode, "DataSourceType",
                                                            ((int)DataPipeSourceType.FileProvider).ToString()));
                component.DbProvider =
                    (DataProviderType)
                    int.Parse(XmlDataUtil.GetAttributeValue(xNode, "DbProviderType",
                                                            ((int)DataProviderType.MSSQL).ToString()));
                component.ConnStr = XmlDataUtil.GetAttributeValue(xNode, "ConnStr", "");
                component.SelectSql = XmlDataUtil.GetAttributeValue(xNode, "SelectSql", "");
                component.GroupBy = XmlDataUtil.GetAttributeValue(xNode, "GroupBy", "");
                component.SortBy = XmlDataUtil.GetAttributeValue(xNode, "SortBy", "");
                component.TblName = XmlDataUtil.GetAttributeValue(xNode, "TableName", "");
                component.RootFolderPath = XmlDataUtil.GetAttributeValue(xNode, "TableName", "");
                component.FileFilter = XmlDataUtil.GetAttributeValue(xNode, "FileFilter", "");
                component.FolderSearchOption =
                    (SearchOption)
                    int.Parse(XmlDataUtil.GetAttributeValue(xNode, "SearchOption",
                                                            ((int)SearchOption.TopDirectoryOnly).ToString()));

                component.SerializationMethod =
                    (DataPipeSerializationMethod)
                    int.Parse(XmlDataUtil.GetAttributeValue(xNode, "SerializationMethod",
                                                            ((int)DataPipeSerializationMethod.SaveToDB).ToString()));
                component.CustomTypeAssemblyPath = XmlDataUtil.GetAttributeValue(xNode, "CustomAssemblyFilePath", "");
                component.CustomTypeName = XmlDataUtil.GetAttributeValue(xNode, "CustomTypeName", "");
                component.TgtDbProvider =
                    (DataProviderType)
                    int.Parse(XmlDataUtil.GetAttributeValue(xNode, "TgtDbProvider",
                                                            ((int)DataProviderType.MSSQL).ToString()));
                component.TgtConnStr = XmlDataUtil.GetAttributeValue(xNode, "TgtConnStr", "");
                component.TgtFolderPath = XmlDataUtil.GetAttributeValue(xNode, "TgtFolderPath", "");
                component.TgtFileNameFormat = XmlDataUtil.GetAttributeValue(xNode, "TgtFileNamePattern", "");


                component.DataCleaningRules = null;
                XmlNodeList ruleNodes = xNode.SelectNodes("//DataCleaningRule");
                if (ruleNodes != null && ruleNodes.Count > 0)
                {
                    component.DataCleaningRules = new List<DataCleaningRule>();
                    foreach (XmlNode ruleNode in ruleNodes)
                    {
                        DataCleaningRule rule = new DataCleaningRule();
                        rule.DataCleaningRuleID =
                            new Guid(XmlDataUtil.GetAttributeValue(ruleNode, "DataCleaningRuleID", Guid.Empty.ToString()));
                        rule.RuleName = XmlDataUtil.GetAttributeValue(ruleNode, "RuleName", string.Empty);
                        rule.ExternalReferences =
                            StringUtil.Split(XmlDataUtil.GetAttributeValue(ruleNode, "ExternalReferences", string.Empty));
                        rule.ObjectTypeNameToEvaluate = XmlDataUtil.GetAttributeValue(ruleNode, "TypeNameToEvaluate",
                                                                                      string.Empty);
                        rule.CodeSnippet = XmlDataUtil.GetAttributeValue(ruleNode, "CodeSnippet", string.Empty);
                        rule.TrueAction =
                            (DataFlowAction)
                            int.Parse(XmlDataUtil.GetAttributeValue(ruleNode, "TrueAction",
                                                                    ((int)DataFlowAction.MoveToNext).ToString()));
                        rule.FalseAction =
                            (DataFlowAction)
                            int.Parse(XmlDataUtil.GetAttributeValue(ruleNode, "FalseAction",
                                                                    ((int)DataFlowAction.BreakToEnd).ToString()));
                        component.DataCleaningRules.Add(rule);
                    }
                }
                
                return component;
            }
            else
            { 
                throw new Exception("Unable to instantiate email: invalid type specified in xml node");
            }
        }
    }
}
